/*******************************************************************************
 *  Copyright (c) 2010 Chase Technology Ltd.
 *  
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU General Public License v3.0
 *  which is available at http://www.gnu.org/licenses/
 * 
 * Contributors:
 *     Doug Satchwell - initial API and implementation
 *******************************************************************************/
package org.jfunction.ui.internal.editor;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IEditorActionBarContributor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.forms.editor.FormEditor;
import org.eclipse.ui.forms.editor.IFormPage;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.part.MultiPageEditorSite;
import org.jfunction.ui.internal.JFunctionUIConstants;
import org.jfunction.ui.internal.JFunctionUIPlugin;
import org.jfunction.ui.model.UIExample;
import org.jfunction.ui.model.UIScenario;
import org.jfunction.ui.model.UIStep;

public class JFunctionEditor extends FormEditor{

	private static final String F_DIALOG_EDITOR_SECTION_KEY = "jfunction-form-editor"; //$NON-NLS-1$

	private SourcePage sourcePage;
	private ScenarioPage scenarioPage;
	private ExamplesPage examplesPage;
	private UIScenario scenario;
	private Clipboard clipboard;
	private Menu fContextMenu;
	private String fLastActivePageId;
	
	private static class JFunctionMultiPageEditorSite extends MultiPageEditorSite {
		public JFunctionMultiPageEditorSite(MultiPageEditorPart multiPageEditor, IEditorPart editor) {
			super(multiPageEditor, editor);
		}

		@Override
		public IEditorActionBarContributor getActionBarContributor() {
			JFunctionEditor editor = (JFunctionEditor) getMultiPageEditor();
			JFunctionEditorActionContributor contributor = editor.getContributor();
			return contributor.getSourceContributor();
		}

		@Override
		public IWorkbenchPart getPart() {
			return getMultiPageEditor();
		}
	}
	
	@Override
	protected IEditorSite createSite(IEditorPart editor) {
		return new JFunctionMultiPageEditorSite(this, editor);
	}
	
	@Override
	protected void createPages() {
		clipboard = new Clipboard(getContainer().getDisplay());
		MenuManager manager = new MenuManager();
		IMenuListener listener = new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				contextMenuAboutToShow(manager);
			}
		};
		manager.setRemoveAllWhenShown(true);
		manager.addMenuListener(listener);
		fContextMenu = manager.createContextMenu(getContainer());
		getContainer().setMenu(fContextMenu);
		//createInputContexts(fInputContextManager);
		super.createPages();
		//fInputContextManager.addInputContextListener(this);
		String pageToShow = computeInitialPageId();
		if (pageToShow != null)
			setActivePage(pageToShow);
		updateTitle();
		if (getPageCount() == 1 && getContainer() instanceof CTabFolder) {
			((CTabFolder) getContainer()).setTabHeight(0);
		}

//		PDEModelUtility.connect(this);
	}
	
	public void updateTitle() {
		firePropertyChange(IWorkbenchPart.PROP_TITLE);
	}
	
	protected void contextMenuAboutToShow(IMenuManager manager) {
		JFunctionEditorActionContributor contributor = getContributor();
		IFormPage page = getActivePageInstance();
//		if (page instanceof PDEFormPage)
//			((PDEFormPage) page).contextMenuAboutToShow(manager);
		if (contributor != null)
			contributor.contextMenuAboutToShow(manager);
	}
	
	@Override
	protected void addPages() {
		sourcePage = new SourcePage(this, "source", "Source");
		scenarioPage = new ScenarioPage(this, "scenario", "Scenario");
		examplesPage = new ExamplesPage(this, "examples", "Examples");
		try {
			addPage(scenarioPage);
			addPage(examplesPage);
			addPage(sourcePage,getEditorInput());
		} catch (PartInitException e) {
			JFunctionUIPlugin.log(e);
		}
	}
	
	@Override
	protected void setInput(IEditorInput input) {
		// TODO Auto-generated method stub
		super.setInput(input);
		this.scenario = new UIScenario();
		scenario.addStep(new UIStep("org.doug", "Step1", "This is step1"));
		scenario.addStep(new UIStep("org.doug", "Step2", "This is step2 with <field1> (which is a String)"));
		UIExample example1 = new UIExample();
		example1.setValue("field1", "value1");
		scenario.addExample(example1);
		UIExample example2 = new UIExample();
		example1.setValue("field1", "value2");
		scenario.addExample(example2);
	}
	
	@Override
	public void editorDirtyStateChanged() {
		super.editorDirtyStateChanged();
		JFunctionEditorActionContributor contributor = getContributor();
		if (contributor != null)
			contributor.updateActions();
	}
	
	public JFunctionEditorActionContributor getContributor() {
		return (JFunctionEditorActionContributor) getEditorSite().getActionBarContributor();
	}

	@Override
	public void doSave(IProgressMonitor arg0) {
		sourcePage.doSave(arg0);
	}

	@Override
	public void doSaveAs() {
		sourcePage.doSaveAs();
	}

	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}

	UIScenario getScenario() {
		return scenario;
	}

	public void setSelection(ISelection selection) {
		getSite().getSelectionProvider().setSelection(selection);
		getContributor().updateSelectableActions(selection);
	}

	public ISelection getSelection() {
		return getSite().getSelectionProvider().getSelection();
	}
	
	protected void performGlobalAction(String id) {
		// preserve selection
		ISelection selection = getSelection();
//		boolean handled = ((PDEFormPage) getActivePageInstance()).performGlobalAction(id);
//		if (!handled) {
//			IFormPage page = getActivePageInstance();
//			if (page instanceof PDEFormPage) {
//				if (id.equals(ActionFactory.UNDO.getId())) {
//					fInputContextManager.undo();
//					return;
//				}
//				if (id.equals(ActionFactory.REDO.getId())) {
//					fInputContextManager.redo();
//					return;
//				}
//				if (id.equals(ActionFactory.CUT.getId()) || id.equals(ActionFactory.COPY.getId())) {
//					copyToClipboard(selection);
//					return;
//				}
//			}
//		}
	}

	/**
	 * @param selection
	 */
	private void copyToClipboard(ISelection selection) {
//		Object[] objects = null;
//		String textVersion = null;
//		if (selection instanceof IStructuredSelection) {
//			IStructuredSelection ssel = (IStructuredSelection) selection;
//			if (ssel == null || ssel.size() == 0)
//				return;
//			objects = ssel.toArray();
//			StringWriter writer = new StringWriter();
//			PrintWriter pwriter = new PrintWriter(writer);
//			Class objClass = null;
//			for (int i = 0; i < objects.length; i++) {
//				Object obj = objects[i];
//				if (objClass == null)
//					objClass = obj.getClass();
//				else if (objClass.equals(obj.getClass()) == false)
//					return;
//				if (obj instanceof IWritable) {
//					// Add a customized delimiter in between all serialized
//					// objects to format the text representation
//					if ((i != 0) && (obj instanceof IWritableDelimiter)) {
//						((IWritableDelimiter) obj).writeDelimeter(pwriter);
//					}
//					((IWritable) obj).write("", pwriter); //$NON-NLS-1$
//				} else if (obj instanceof String) {
//					// Delimiter is always a newline
//					pwriter.println((String) obj);
//				}
//			}
//			pwriter.flush();
//			textVersion = writer.toString();
//			try {
//				pwriter.close();
//				writer.close();
//			} catch (IOException e) {
//			}
//		} else if (selection instanceof ITextSelection) {
//			textVersion = ((ITextSelection) selection).getText();
//		}
//		if ((textVersion == null || textVersion.length() == 0) && objects == null)
//			return;
//		// set the clipboard contents
//		Object[] o = null;
//		Transfer[] t = null;
//		if (objects == null) {
//			o = new Object[] {textVersion};
//			t = new Transfer[] {TextTransfer.getInstance()};
//		} else if (textVersion == null || textVersion.length() == 0) {
//			o = new Object[] {objects};
//			t = new Transfer[] {ModelDataTransfer.getInstance()};
//		} else {
//			o = new Object[] {objects, textVersion};
//			t = new Transfer[] {ModelDataTransfer.getInstance(), TextTransfer.getInstance()};
//		}
//		clipboard.setContents(o, t);
	}

	public boolean canPasteFromClipboard() {
//		IFormPage page = getActivePageInstance();
//		if (page instanceof PDEFormPage) {
//			return ((PDEFormPage) page).canPaste(getClipboard());
//		}
		return false;
	}

	public boolean canCopy(ISelection selection) {
		if (selection == null)
			return false;
		if (selection instanceof IStructuredSelection)
			return !selection.isEmpty();
		if (selection instanceof ITextSelection) {
			ITextSelection textSelection = (ITextSelection) selection;
			return textSelection.getLength() > 0;
		}
		return false;
	}

	public boolean canCut(ISelection selection) {
		return canCopy(selection);
	}

	void updateUndo(IAction undoAction, IAction redoAction) {
//		IModelUndoManager undoManager = fInputContextManager.getUndoManager();
//		if (undoManager != null)
//			undoManager.setActions(undoAction, redoAction);
	}



	public void doRevert() {
		// TODO Auto-generated method stub
		
	}
	
	protected String computeInitialPageId() {
		String firstPageId = null;
		String storedFirstPageId = loadDefaultPage();
		if (storedFirstPageId != null)
			firstPageId = storedFirstPageId;
		// Regardless what is the stored value,
		// use source page if model is not valid
//		String invalidContextId = getFirstInvalidContextId();
//		if (invalidContextId != null)
//			return invalidContextId;
		return firstPageId;
	}
	
	/**
	 * @param pageID
	 */
	protected void setDialogEditorPageKey(String pageID) {
		// Use one global setting for all files belonging to a given editor
		// type.  Use the editor ID as the key.
		// Could use the storage editor input to get the underlying file
		// and use it as a unique key; but, the dialog settings file will
		// grow out of control and we do not need that level of granularity
		IDialogSettings section = getSettingsSection();
		section.put(getEditorID(), pageID);
	}

	/**
	 * 
	 */
	protected String getDialogEditorPageKey() {
		// Use one global setting for all files belonging to a given editor
		// type.  Use the editor ID as the key.
		// Could use the storage editor input to get the underlying file
		// and use it as a unique key; but, the dialog settings file will
		// grow out of control and we do not need that level of granularity
		IDialogSettings section = getSettingsSection();
		return section.get(getEditorID());
	}
	
	private IDialogSettings getSettingsSection() {
		// Store global settings that will persist when the editor is closed
		// in the dialog settings (This is cheating)
		// Get the dialog settings
		IDialogSettings root = JFunctionUIPlugin.getDefault().getDialogSettings();
		// Get the dialog section reserved for PDE form editors
		IDialogSettings section = root.getSection(F_DIALOG_EDITOR_SECTION_KEY);
		// If the section is not defined, define it
		if (section == null) {
			section = root.addNewSection(F_DIALOG_EDITOR_SECTION_KEY);
		}
		return section;
	}

	/**
	 * @return
	 */
	protected String getEditorID(){
		return JFunctionUIConstants.EDITOR_ID;
	}

	/**
	 * @param input
	 * @param pageId
	 */
	protected void setPropertyEditorPageKey(IFileEditorInput input, String pageId) {
		// We are using the file itself to persist the editor page key property
		// The value persists even after the editor is closed
		IFile file = input.getFile();
		try {
			// Set the editor page ID as a persistent property on the file
			file.setPersistentProperty(JFunctionUIConstants.PROPERTY_EDITOR_PAGE_KEY, pageId);
		} catch (CoreException e) {
			// Ignore
		}
	}

	/**
	 * @return
	 */
	private String loadDefaultPage() {
		IEditorInput input = getEditorInput();
		if (input instanceof IFileEditorInput) {
			// Triggered by opening a file in the workspace
			// e.g. From the Package Explorer View
			return getPropertyEditorPageKey((IFileEditorInput) input);
		} else if (input instanceof IStorageEditorInput) {
			// Triggered by opening a file NOT in the workspace
			// e.g. From the Plug-in View
			return getDialogEditorPageKey();
		}
		return null;
	}

	/**
	 * @param input
	 * @return
	 */
	protected String getPropertyEditorPageKey(IFileEditorInput input) {
		// We are using the file itself to persist the editor page key property
		// The value persists even after the editor is closed
		IFile file = input.getFile();
		// Get the persistent editor page key from the file
		try {
			return file.getPersistentProperty(JFunctionUIConstants.PROPERTY_EDITOR_PAGE_KEY);
		} catch (CoreException e) {
			return null;
		}
	}
	
	protected void pageChange(int newPageIndex) {
		super.pageChange(newPageIndex);
		IFormPage page = getActivePageInstance();
//		updateContentOutline(page);
		if (page != null) {
			fLastActivePageId = page.getId();
		}
	}
	
	private void storeDefaultPage() {
		IEditorInput input = getEditorInput();
		String pageId = fLastActivePageId;
		if (pageId == null)
			return;
		if (input instanceof IFileEditorInput) {
			// Triggered by opening a file in the workspace
			// e.g. From the Package Explorer View
			setPropertyEditorPageKey((IFileEditorInput) input, pageId);
		} else if (input instanceof IStorageEditorInput) {
			// Triggered by opening a file NOT in the workspace
			// e.g. From the Plug-in View
			setDialogEditorPageKey(pageId);
		}
	}

	@Override
	public void dispose() {
		storeDefaultPage();
		super.dispose();
	}
}
